package etrgo

import (
	"bytes"
	"html/template"
	"reflect"
	"time"
)

// Equal is a helper for comparing value equality, following these rules:
//  - Values with equivalent types are compared with reflect.DeepEqual
//  - int, uint, and float values are compared without regard to the type width.
//    for example, Equal(int32(5), int64(5)) == true
//  - strings and byte slices are converted to strings before comparison.
//  - else, return false.
func Equal(a, b interface{}) bool {
	Debug("call equal.")
	if reflect.TypeOf(a) == reflect.TypeOf(b) {
		return reflect.DeepEqual(a, b)
	}
	switch a.(type) {
	case int, int8, int16, int32, int64:
		switch b.(type) {
		case int, int8, int16, int32, int64:
			return reflect.ValueOf(a).Int() == reflect.ValueOf(b).Int()
		}
	case uint, uint8, uint16, uint32, uint64:
		switch b.(type) {
		case uint, uint8, uint16, uint32, uint64:
			return reflect.ValueOf(a).Uint() == reflect.ValueOf(b).Uint()
		}
	case float32, float64:
		switch b.(type) {
		case float32, float64:
			return reflect.ValueOf(a).Float() == reflect.ValueOf(b).Float()
		}
	case string:
		switch b.(type) {
		case []byte:
			return a.(string) == string(b.([]byte))
		}
	case []byte:
		switch b.(type) {
		case string:
			return b.(string) == string(a.([]byte))
		}
	}
	return false
}

func Gt(a, b interface{}) bool {
	switch a.(type) {
	case int, int8, int16, int32, int64:
		switch b.(type) {
		case int, int8, int16, int32, int64:
			return reflect.ValueOf(a).Int() > reflect.ValueOf(b).Int()
		}
	case uint, uint8, uint16, uint32, uint64:
		switch b.(type) {
		case uint, uint8, uint16, uint32, uint64:
			return reflect.ValueOf(a).Uint() > reflect.ValueOf(b).Uint()
		}
	case float32, float64:
		switch b.(type) {
		case float32, float64:
			return reflect.ValueOf(a).Float() > reflect.ValueOf(b).Float()
		}
	}
	return false
}

func Set(renderArgs map[string]interface{}, key string, value interface{}) template.HTML {
	renderArgs[key] = value
	return template.HTML("")
}

func Append(renderArgs map[string]interface{}, key string, value interface{}) template.HTML {
	if renderArgs[key] == nil {
		renderArgs[key] = []interface{}{value}
	} else {
		renderArgs[key] = append(renderArgs[key].([]interface{}), value)
	}
	return template.HTML("")
}

func Time(date time.Time) string {
	return date.Format("2006/01/02 15:04:05")
}

func Timestamp(timestamp int64) string {
	return time.Unix(timestamp,0).Format("2006/01/02 15:04:05");
}

func Include(name string, args...string) template.HTML {
	loader := AppRouter.Loader

	subTemplate := loader.Lookup(name)
	
	if subTemplate == nil {
		Error("the fragement of file is null[templateName=%s].", name)
		return ""
	}

	contentBuffer := bytes.NewBufferString("")

    var data map[string]string

    if len(args) > 0 {
    	data = make(map[string]string)
    	var key, value string
		for i, v := range args {
			if i % 2 == 0 {
				key =  v 
			}else {
				value = v 
				data[key] = value 
			}
		}
    }
    
	err := subTemplate.Execute(contentBuffer, data)

	if err == nil {
		Debug("the render conent:%s.", contentBuffer.String())
		//tplContent := contentBuffer.String()
		return template.HTML(contentBuffer.String())
	} else {
		Error("failed to render the fragment of file[%s,err=%s].", name,err)
	}
	return ""
}
